#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>
#include <sys/stat.h>
#include "resource.h"
#include "func.h"
#include "lang.h"
#include "mhbtn.h"
#include "mhlabel.h"
#include "mhctrlstate.h"
#include "mhedit.h"
#include "mhstatic.h"
#include "update.h"
#include "com.h"
#include "progress.h"
#include "info.h"
#include "string.h"
#include "globe.h"
#include "cmd.h"
#include "update_net.h"
#include "md5.h"
#include "des.h"
#include "mh/dsp2812.h"

#define SYS1_UPDATE     "mh1_update_net.tar.gz"
#define SYS2_UPDATE     "mh2_update_net.tar.gz"
#define SYS1_UPDATE_DIR "mh1_update_net"
#define SYS2_UPDATE_DIR "mh2_update_net"
#define UPGRADE_JIJIA_PATH  "jijia.mh"
#define  MAX_LINE_BYTE  200

#define UPGRADE_STATE                               0X2015
#define UPGRADE_STATE_CACHU               1
#define UPGRADE_STATE_BIANCHENG     2
#define PERCENT_NUM                                  100

/*
 *主控程序升级
 */
static int GetUpdateFile(char *out, int syscam)
{
    int ret = 0;
    char tmp[MAX_LINE_BYTE] = { 0 };
    if (!HasUsb())
    {
        return -1;
    }

    strcat(out, GetUsbDir());

    if (syscam == 1)
    {
        sprintf(tmp, "%s%s", out, SYS1_UPDATE);
    }
    else
    {
        sprintf(tmp, "%s%s", out, SYS2_UPDATE);
    }

    printf("tmp = %s\n", tmp);
    struct stat buf;
    if(stat(tmp, &buf))
    {
        return -2;
    }
    return ret;
}

static void Reload()
{
    printf("unregister label, btn, edit......\n");
    UnregisterMhBtn();
    UnregisterMhLabel();
    UnregisterMhCtrlState();
    UnregisterMhEdit();
    UnregisterMhStatic();
    printf("unload bmp\n");
    UnloadMemBmp();
    printf("destory knit data\n");
    DestroyKnitData(g_knit_data);
    sleep(1);

    if (fork() == 0)
    {
        printf("fork\n");
        execlp("/root/HQ/mh_ssgui", "/root/HQ/mh_ssgui", NULL);
        exit(0);
    }

    exit(1);
}

int UpgradeApp(char *error, char *progress)
{
    char sc[256] = {0};
    int ret = 0;
    int syscam =  SYS_STYE_CAM;

    if(GetUpdateFile(sc, syscam))
    {
        *error = -1;
         return -1;
    }
    else
    {
        char command[256] = {0};
        char tmp[64] = { 0 };
        printf("sc = %s\n", sc);
        *progress = 15;
        strcat(command, "tar zxvf ");
        strcat(command, sc);
        if (syscam == 1)
        {
            sprintf(tmp, "%s", SYS1_UPDATE);
        }
        else
        {
            sprintf(tmp, "%s", SYS2_UPDATE);
        }
        strcat(command, tmp);

        strcat(command, " -C /tmp/");

        printf("command = %s\n", command);
        system(command);
        *progress = 40;
        if (syscam == 1)
        {
            sprintf(command, ". /tmp/%s/update.sh", SYS1_UPDATE_DIR);
        }
        else
        {
            sprintf(command, "./tmp/%s/update.sh", SYS2_UPDATE_DIR);
        }

        printf("command = %s\n", command);
        system(command);
        *progress = 60;
        Reload();
    }
    return ret;
}

/*
 *机架板升级程序
 */
static int ArmProgramDecrypt(const char *fullpath,char key[8], char prog_out[1024*128],unsigned usage)
{
    int ret = ENC_EOK;
    FILE *f_arm;
    char *buf_fle;
    int size_fle;
    int length;
    unsigned i;
    struct program_head *phead;

    if (prog_out == NULL)
    {
        printf("param: prog_out is NULL");

        return ENC_ENOMEM;
    }

    /* 以二进制方式打开升级文件 */
    if ((f_arm = fopen(fullpath, "rb")) == NULL)
    {
        printf("can't open file: %s\n", fullpath);
        return ENC_EOFF;
    }

    fseek(f_arm, 0, SEEK_END);
    size_fle = ftell(f_arm);
    fseek(f_arm, 0, SEEK_SET);

    if ((buf_fle = (char*)malloc(size_fle)) == NULL)
    {
        printf("alloc buffer fail\n");

        fclose(f_arm);

        return ENC_ENOMEM;
    }

    length = fread(buf_fle, sizeof(char), size_fle, f_arm);
    if (length != size_fle)
    {
        printf("read file fail\n");

        ret = ENC_EFRD;
        goto _exit;
    }

    /**** 还原数据 ****/
    MD5_CTX context;
    char md5[16];
    subkey_t subkey;
    char *program;
    char *in;
    phead = (struct program_head*)buf_fle;

    if (phead->head.magic != FILEHEAD_MAGIC)
    {
        printf("involid file head\n");
        ret = ENC_EINVH;
        goto _exit;
    }
    if (checksum((unsigned short*)&phead->head, sizeof(filehead_t)) != 0xFFFF)
    {
        printf("file head check fail\n");
        ret = ENC_ECHK;
        goto _exit;
    }
    if ((phead->head.check_alg != CHK_ALG_MD5) || (phead->head.encrypt_alg != ENC_ALG_DES))
    {
        printf("can not surport this alg\n");
        ret = ENC_EINVH;
        goto _exit;
    }
    if (usage && (phead->head.usage != usage))
    {
        ret = ENC_EUSAGE;
        goto _exit;
    }

    program = (char *)prog_out;
    in = (char*)buf_fle + phead->head.data_offset;
    DES_MakeSubKey(key, subkey);
    for (i = 0; i < phead->dsize; i += 8)
    {
        DES_DoWork(&in[i], &program[i], subkey, DECRYPT);
    }
    goto _exit;
    printf("MD5...\n");
    MD5Init(&context);
    MD5Update(&context, (unsigned short*)program,phead->dsize);
    MD5Final(&context, md5);
    if (memcmp(md5,phead->md5, 16) != 0)
    {
        printf("file check fail\n");
        ret = ENC_ECHK;
        goto _exit;
    }

_exit:
    fclose(f_arm);
    free(buf_fle);
    return ret;
}

static char *UpgradeFreadData(const char *filename, int *size)
{
    FILE *fd;
    char *buf_file = NULL;

    int size_file;

    if ((fd = fopen(filename, "rb")) == NULL)
    {
        printf("can not open file: %s\n", filename);
        return NULL;
    }

    fseek(fd, 0, SEEK_END);
    size_file = ftell(fd);
    fseek(fd, 0, SEEK_SET);
    *size = size_file;
    if ((buf_file = (char*)malloc(size_file)) == NULL)
    {
        printf("mlloc buffer fail\n");
        fclose(fd);
        return NULL;
    }

    fclose(fd);

    memset(buf_file, 0, size_file);

    if (ArmProgramDecrypt(filename, "31415926", buf_file, USAGE_LPC1788) != ENC_EOK)
    {
        printf("decrypt failed\n");
        free(buf_file);
        return NULL;
    }

    return buf_file;
}

int UpgradeJijia(char *error, char *progress)
{
    int ret = 0;
    char *up_data = NULL;
    char path[100] = {0};
    int file_size = 0;
    char pthread_pause = TRUE;
    uchar state = 0;
    uchar percent = 0;

    ret = SetJustResetJijia(g_knit_data, UPGRADE_STATE);
    if(ret)
    {
        printf("send reset update jijia error \n");
        *error = -1;
        return -1;
    }
    *progress = 5;
     sleep(5);
     strcat(path, GetUsbDir());
     strcat(path, UPGRADE_JIJIA_PATH);
     up_data = UpgradeFreadData(path, &file_size);
     ret = SendJijiaUpgradeFile(g_knit_data, (uchar *)up_data, file_size);
     if(ret)
     {
         printf("send jijia upgrade file error \n");
        *error = -2;
        return -1;
     }
     *progress = 7;
    ret = SetUpgradeJijia(g_knit_data, UPGRADE_STATE);
    if(ret)
    {
        printf("request update jijia error \n");
        *error = -3;
        return -1;
    }
    *progress = 10;
    while(pthread_pause)
    {
        ret = GetUpgradeJijia(g_knit_data, &state, &percent);
        if(ret)
        {
            printf("update query state error \n");
            *error = -4;
            return -1;
        }
        if(state == UPGRADE_STATE_CACHU)
        {
            *progress = percent/4 + 10;
        }
        else if(state == UPGRADE_STATE_BIANCHENG)
        {
            *progress = 35 +percent/2;
            if(percent >= PERCENT_NUM -5)
            {

                break;
            }
        }
    }
    usleep(100000);
    ret = SetJustResetJijia(g_knit_data, UPGRADE_STATE);
    *progress = 90;
    if(ret)
    {
        printf("send reset update jijia error \n");
        *error = -5;
        return -1;
    }
    sleep(5);
//    InitDataFromFile();
    ret = SendGlobalParam(g_knit_data);
    if(ret)
    {
        printf("send init of globe error \n");
        *error = -6;
        return -1;
    }
    *progress = PERCENT_NUM;
    return ret;
}








